﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Clandestine;
using Clandestine.Entities;
using System.Reflection;

namespace Slick.MapEditor.Tools
{
    public class EntityAdder : ITool
    {
        public Map Map;
        public string Name { get { return "Entity Adder"; } }

        /// <summary>
        /// The sprite used for the previews as we drag the mouse.
        /// </summary>
        private static Sprite hoverSprite;

        /// <summary>
        /// Whether the mouse button is being held down.
        /// </summary>
        private bool down = false;

        /// <summary>
        /// The point at which the mouse was pressed down - to allow dragging.
        /// </summary>
        private Point downPosition = new Point();

        public EntityAdder(Map map)
        {
            this.Map = map;
            hoverSprite = new Sprite(Texture.GetTexture("white.png"));
            hoverSprite.Visible = false;
            hoverSprite.Color = new GLColor(0f, 1f, 1f, 0.6f);
        }

        ~EntityAdder()
        {
            hoverSprite.Dispose();
        }

        public void Focus()
        {
        }

        public void Unfocus()
        {
        }

        public void MouseUpLeft(int mouseX, int mouseY, int tileX, int tileY)
        {
            lock (Map.Entities.SelectedEntityTypeBlob)
            {
                // What type of entity are we dealing with?

                // If it's null, we don't want any of that, thank you.
                if (Map.Entities.SelectedEntityType == null)
                    return;

                // Trigger? Would mean we've been dragging a box for it.
                if (Map.Entities.SelectedEntityType.Trigger)
                {
                    // Have we drawn a box?
                    if (down == true) 
                    {
                        // Construct trigger.
                        Trigger ent = ((Trigger)System.Activator.CreateInstance(
                            Assembly.GetAssembly(typeof(Clandestine.Entities.Trigger))
                            .GetType(Map.Entities.SelectedEntityType.FullName)));

                        mouseX += Program.GridSize - (mouseX % Program.GridSize); // Make sure we're on a grid boundary.
                        mouseY += Program.GridSize - (mouseY % Program.GridSize);


                        // get co-ords of top left of the selection - note, we can move the mouse behind the original point
                        // so must handle this!
                        Point topLeft = new Point();
                        topLeft.X = (mouseX < downPosition.X ? mouseX : downPosition.X);
                        topLeft.Y = (mouseY < downPosition.Y ? mouseY : downPosition.Y);

                        // get co-ords of the bottom right
                        Point bottomRight = new Point();
                        bottomRight.X = (mouseX > downPosition.X ? mouseX : downPosition.X);
                        bottomRight.Y = (mouseY > downPosition.Y ? mouseY : downPosition.Y);

                        hoverSprite.Visible = false;

                        // Finish constructing trigger.
                        ent.Position = new System.Drawing.Point(topLeft.X, topLeft.Y);
                        ent.Size = new System.Drawing.Size(bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
                        ent.UUID = System.Guid.NewGuid().ToString();
                        ent.Layer = (float)Map.Layers.SelectedLayer.Depth;

                        // Add entity.
                        Map.Entities.Add(ent);
                        Map.Entities.SelectEntity(ent);
                    }
                }
            }

            down = false;
            downPosition = new Point(-1, -1);
        }

        public void MouseDownLeft(int mouseX, int mouseY, int tileX, int tileY)
        {
            mouseX -= (mouseX % Program.GridSize); // Make sure that  we're on a grid boundary.
            mouseY -= (mouseY % Program.GridSize);

            lock (Map.Entities.SelectedEntityTypeBlob)
            {
                // What type of entity are we adding?

                // No selected entity? No thanks.
                if (Map.Entities.SelectedEntityType == null)
                    return;

                // If it's a trigger, we'll have to start drawing a box.
                if (Map.Entities.SelectedEntityType.Trigger)
                {
                    // Remember we went down
                    down = true;
                    downPosition = new Point(mouseX, mouseY);

                    // Show a preview hover.
                    hoverSprite.Visible = true;
                    hoverSprite.Position = new System.Drawing.Point(mouseX, mouseY);
                    hoverSprite.ScaleX = 0f;
                    hoverSprite.ScaleY = 0f;
                    hoverSprite.Layer = 5000000;
                }
                else // Otherwise, it's a normal entity.
                {
                    // Construct the entity
                    Entity ent = ((Entity)System.Activator.CreateInstance(
                        Assembly.GetAssembly(typeof(Clandestine.Entities.Entity))
                        .GetType(Map.Entities.SelectedEntityType.FullName)));
                    ent.Position = new System.Drawing.Point(mouseX, mouseY);
                    ent.UUID = System.Guid.NewGuid().ToString();
                    ent.Layer = (float)Map.Layers.SelectedLayer.Depth;
                    
                    // Add entity and select it for property window.
                    Map.Entities.Add(ent);
                    Map.Entities.SelectEntity(ent);
                }
            }
        }

        public void MouseUpRight(int mouseX, int mouseY, int tileX, int tileY)
        {
        }

        public void MouseDownRight(int mouseX, int mouseY, int tileX, int tileY)
        {
            // Cancel drawing a trigger
            down = false;
            downPosition = new Point(-1, -1);
            hoverSprite.Visible = false;
        }

        public void MouseMove(int mouseX, int mouseY, int tileX, int tileY)
        {
            // Are we drawing a trigger?
            if (down)
            {
                mouseX = ((int)(mouseX / Camera.Zoom + Camera.Position.X)); // work out tileX/Y (even though we're given it...
                mouseY = ((int)(mouseY / Camera.Zoom + Camera.Position.Y));

                mouseX += Program.GridSize - (((int)(mouseX / Camera.Zoom)) % Program.GridSize); // rounding errors in finding tileX/Y, so we fix them
                mouseY += Program.GridSize - (((int)(mouseY / Camera.Zoom)) % Program.GridSize);

                // get co-ords of top left of the selection - note, we can move the mouse behind the original point
                // so must handle this!
                Point topLeft = new Point();
                topLeft.X = (mouseX < downPosition.X ? mouseX : downPosition.X);
                topLeft.Y = (mouseY < downPosition.Y ? mouseY : downPosition.Y);

                // get co-ords of the bottom right
                Point bottomRight = new Point();
                bottomRight.X = (mouseX > downPosition.X ? mouseX : downPosition.X);
                bottomRight.Y = (mouseY > downPosition.Y ? mouseY : downPosition.Y);

                hoverSprite.Visible = true;
                hoverSprite.ScaleX = (bottomRight.X - topLeft.X);
                hoverSprite.ScaleY = (bottomRight.Y - topLeft.Y);
                hoverSprite.Position = new Point(topLeft.X, topLeft.Y);
                hoverSprite.Layer = 5000000;
            }
        }
    }
}
